package com.apes.scm.voucher.model;

import com.alibaba.fastjson.annotation.JSONField;
import com.apes.framework.jpa.DefaultPersistListener;
import com.apes.framework.jpa.Model;
import com.apes.framework.jpa.comment.Comment;
import com.apes.framework.jpa.generator.ApesGenerator;
import com.apes.framework.jpa.tuple.date.DateTime;
import com.apes.framework.util.ApesConst;
import com.apes.framework.util.DateUtil;
import com.apes.framework.util.MD5Util;
import com.apes.scm.account.account.model.Cooperation;
import com.apes.scm.account.account.model.InventoryBatch;
import com.apes.scm.account.tax.model.Tax;
import com.apes.scm.contract.model.Contract;
import com.apes.scm.masterdata.frame.model.Dept;
import com.apes.scm.masterdata.party.model.PartyRole;
import com.apes.scm.masterdata.product.model.Product;
import com.apes.scm.masterdata.product.model.ProductUom;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
import org.hibernate.annotations.DynamicInsert;
import org.hibernate.annotations.DynamicUpdate;
import org.hibernate.annotations.SelectBeforeUpdate;

import javax.persistence.*;
import javax.validation.constraints.NotNull;
import java.util.Date;
import java.util.Objects;

/**
 * 功能：凭证价值评估明细
 *
 * @author xul
 * @create 2018-02-11 10:56
 */
@Getter
@Setter
@SelectBeforeUpdate
@DynamicInsert
@DynamicUpdate
@Entity
@EntityListeners(DefaultPersistListener.class)
@Table(name = VoucherInventory.CONST_TABLE_NAME, indexes = {
        @Index(name = "idx_inventory_voucher_id", columnList = "voucher_id"),
        @Index(name = "idx_inventory_voucher_item_id", columnList = "voucher_item_id")})
public class VoucherInventory extends Model {
    public static final String CONST_TABLE_NAME = "acc_voucher_inventory";

    @Id
    @Column(name = "id")
    @ApesGenerator(code = CONST_TABLE_NAME, name = "凭证价值评估明细")
    @Comment("单号")
    private long id;

    @NotNull
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "company_id", referencedColumnName = "id")
    @Comment("公司编码")
    private PartyRole company;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "dept_id", referencedColumnName = "id", nullable = false)
    @Comment("采购部门编码")
    private Dept dept;

    @NotNull
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "voucher_id", referencedColumnName = "id")
    @Comment("凭证单号")
    private Voucher voucher;

    @NotNull
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "voucher_item_id", referencedColumnName = "id")
    @Comment("凭证明细单号")
    private VoucherItem voucherItem;

    @NotNull
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "partner_id", referencedColumnName = "id")
    @Comment("业务伙伴编码")
    private PartyRole partner;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "inventory_id", referencedColumnName = "id")
    @Comment("商品库存价值内码")
    private InventoryBatch inventoryBatch;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "inventory_cooperation_id", referencedColumnName = "id", nullable = false)
    @Comment("库存合作方式编码")
    private Cooperation inventoryCooperation;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "inventory_supplier_id", referencedColumnName = "id", nullable = false)
    @Comment("库存供应商编码")
    private PartyRole inventorySupplier;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "inventory_dept_id", referencedColumnName = "id", nullable = false)
    @Comment("库存采购部门编码")
    private Dept inventoryDept; //

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "inventory_contract_id", referencedColumnName = "id")
    @Comment("采购合同编码")
    private Contract inventoryContract;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "tax_id", referencedColumnName = "id", nullable = false)
    @Comment("税率编码")
    private Tax tax;

    @Column(name = "is_temporary", nullable = false)
    @Comment("是否暂估")
    private boolean isTemporary = false;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "product_id", referencedColumnName = "id", nullable = false)
    @Comment("商品编码")
    private Product product;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "product_uom_id", referencedColumnName = "id", nullable = false)
    @Comment("计量单位编码")
    private ProductUom uom;

    @Column(name = "product_qty", nullable = false, columnDefinition = ApesConst.FIELD_QTY_16_4_0)
    @Comment("数量")
    private double productQty = 0;

    @Column(name = "qty_returned", nullable = false, columnDefinition = ApesConst.FIELD_QTY_16_4_0)
    @Comment("已退货数量（销售凭证中使用）")
    private double qtyReturned = 0;

    @Column(name = "price_unit", nullable = false, columnDefinition = ApesConst.FIELD_MONEY_16_4_0)
    @Comment("含税单价")
    private double priceUnit = 0;

    @Column(name = "tax_cost_price", nullable = false, columnDefinition = ApesConst.FIELD_MONEY_16_4_0)
    @Comment("含税成本单价")
    private Double taxCostPrice;

    @JSONField(format = DateUtil.SHOW_DATE_FORMAT)
    @Temporal(TemporalType.DATE)
    @Column(name = "accounting_date", nullable = false)
    @Comment("记帐日期")
    private Date accountingDate;

    public void changeProductQty(double changeQty) {
        int sign = voucher.isReturned() ? -1 : 1;
        this.productQty += sign * Math.abs(changeQty);
    }

    public String createGroupingKey() {
        StringBuffer sb = new StringBuffer();
        sb.append(getInventorySupplier().getId()).append("#")
                .append(getInventoryDept().getId()).append("#")
                .append(getInventoryCooperation().getId());
        if (getInventoryContract() != null) {
            sb.append("#").append(getInventoryContract().getId());
        }
        return MD5Util.encrypt(sb.toString());
    }

    /**
     * 增加已退货数量
     */
    public void incQtyReturned(double qtyReturned) {
        if ((this.qtyReturned + qtyReturned) > productQty) {
            throw new RuntimeException("已退货数量之和不能大于可退货数量，当前可退数量：" + (productQty - this.qtyReturned));
        }
        this.qtyReturned += qtyReturned;
    }

    @Transient
    private double frostQty = 0; //冻结退货数量

    /*
     * 功能：更新冻结数量
     */
    public void changeFrostQty(double changeQty) {
        this.frostQty += changeQty;
        if (this.frostQty < 0) throw new RuntimeException("冻结数量不允许小于零！");
        if (this.frostQty > getProductQty() - getQtyReturned()) throw new RuntimeException("冻结数量不能大于销售数量！");
    }
}
